home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Megahits 3
/
Megahits 3 (1994)(GTI - Rhein-Main-Soft)(DE)[!].iso
/
denkspiele
/
amigo
/
goplayer.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-14
|
53KB
|
1,519 lines
/* The go player */
/* Ported from Pascal to C by Todd R. Johnson 4/17/88 */
/* From the original pascal file:
Go Move Generator
Copyright (c) 1983 by Three Rivers Computer Corp.
Written: January 17, 1983 by Stoney Ballard
Edit History:
*/
#include "go.h"
#include "goplayutils.h"
#define BIGGEST 32767 /* maximum value for short */
/* From go.c */
extern struct bRec goboard[19][19];
extern short ko, koX, koY;
/* From goplayutils.c */
extern intBoard bord;
extern intBoard ndbord;
extern intBoard claim;
extern intBoard legal;
extern intBoard connectMap;
extern intBoard threatBord;
extern short maxGroupID;
extern short treeLibLim;
extern short killFlag;
extern short depthLimit;
extern short showTrees;
extern short utilPlayLevel;
extern groupRec gList[maxGroup];
extern short sGlist[maxGroup + 1];
extern pointList pList;
extern pointList pList1;
extern pointList plist2;
extern pointList plist3;
extern intBoard groupIDs;
extern intBoard protPoints;
extern sType mySType;
extern spanGroup( short, short, pointList * );
extern genState();
extern initGPUtils();
/* procedure headers */
genBord(enum bVal);
/* copyArray( (short *) *, (short *) * ); */
short getMove( short *, short * );
short genMove( enum bVal, short *, short * );
short checkPos( short, short, short );
short takeCorner( short *, short * );
short extend( short *, short * );
short noNbrs( short, short );
short extend2( short *, short * );
short lookForSave( short *, short * );
short lookForSaveN( short *, short * );
short lookForKill( short *, short * );
short doubleAtari( short *, short * );
short lookForAttack( short *, short * );
short threaten( short *, short * );
short connectCut( short *, short * );
short heCanCut( short, short );
short safeMove( short, short );
short extendWall( short *, short * );
short findAttack2( short *, short * );
short blockCut( short *, short * );
short cutHim( short *, short * );
short atariAnyway( short *, short * );
short underCut( short *, short * );
short dropToEdge( short *, short * );
short pushWall( short *, short * );
short reduceHisLiberties( short *, short * );
short dropToEdge2( short *, short * );
short saveNLibs;
pointList dapList1, dapList2, dapList3;
char *playReason;
short maxPlayLevel = 7;
short playLevel = 7;
genBord(color)
enum bVal color;
{
short x, y, nomoves = TRUE;
maxPlayLevel = 7;
utilPlayLevel = playLevel;
mySType = color;
if (playLevel < 2)
treeLibLim = 2;
else
treeLibLim = 3;
depthLimit = 100;
for (y = 0; y <= 18; y++)
for (x = 0; x <= 18; x++)
if (goboard[x][y].Val == color)
{
bord[x][y] = 1;
legal[x][y] = FALSE;
nomoves = FALSE;
}
else if (goboard[x][y].Val == EMPTY)
{
bord[x][y] = 0;
legal[x][y] = TRUE;
}
else
{
bord[x][y] = -1;
legal[x][y] = FALSE;
nomoves = FALSE;
}
if (ko) legal[koX][koY] = FALSE;
if (! nomoves)
genState();
else
{
initGPUtils();
}
}
short getMove( x, y )
short *x, *y;
{
if (takeCorner(x, y)) return TRUE;
if (lookForSave(x, y)) return TRUE;
if (lookForSaveN(x, y)) return TRUE;
if (extend(x, y)) return TRUE;
if (lookForKill(x, y)) return TRUE;
if (doubleAtari(x, y)) return TRUE;
if (lookForAttack(x, y)) return TRUE;
if (threaten(x, y)) return TRUE;
if (extend2(x, y)) return TRUE;
if (connectCut(x, y)) return TRUE;
if (blockCut(x, y)) return TRUE;
if (cutHim(x, y)) return TRUE;
if (extendWall(x, y)) return TRUE;
if (findAttack2(x, y)) return TRUE;
if (atariAnyway(x, y)) return TRUE;
if (underCut(x, y)) return TRUE;
if (dropToEdge(x, y)) return TRUE;
if (pushWall(x, y)) return TRUE;
if (reduceHisLiberties(x, y)) return TRUE;
if (dropToEdge2(x, y)) return TRUE;
return FALSE;
}
short genMove( color, x, y )
enum bVal color;
short *x, *y;
{
if (playLevel > 2)
saveNLibs = TRUE;
else
saveNLibs = FALSE;
genBord(color);
if (getMove(x, y))
return TRUE;
return FALSE;
}
short checkPos(x, y, field)
short x, y, field;
{
short ok;
ok = (((field == 0) && (claim[x][y] == 0)) ||
((field > 0) &&
(claim[x][y] >= 0) && (claim[x][y] <= field)) ||
((field < 0) &&
(claim[x][y] <= 0) && (claim[x][y] >= field))) &&
(bord[x-1][y] == 0) &&
(bord[x+1][y] == 0) &&
(bord[x][y-1] == 0) &&
(bord[x][y+1] == 0);
if (ok) return TRUE; else return FALSE;
}
short takeCorner( x, y )
short *x, *y;
{
short field = -1, i;
i = 18 - 3;
playReason = "takeCorner";
while (field != -4)
{
if (field == -1) field = 0;
else if (field == 0) field = 4;
else field = -4;
if (checkPos(2, 3, field)) { *x = 2; *y = 3; return TRUE; }
if (checkPos(3, 2, field)) { *x = 3; *y = 2; return TRUE; }
if (checkPos(2, i, field)) { *x = 2; *y = i; return TRUE; }
if (checkPos(3, i + 1, field)) { *x = 3; *y = i+1; return TRUE; }
if (checkPos(i, i + 1, field)) { *x = i; *y = i+1; return TRUE; }
if (checkPos(i + 1, i, field)) { *x = i+1; *y = i; return TRUE; }
if (checkPos(i, 2, field)) { *x = i; *y = 2; return TRUE; }
if (checkPos(i + 1, 3, field)) { *x = i+1; *y = 3; return TRUE; }
if (checkPos(2, 4, field)) { *x = 2; *y = 4; return TRUE; }
if (checkPos(4, 2, field)) { *x = 4; *y = 2; return TRUE; }
if (checkPos(2, i - 1, field)) { *x = 2; *y = i-1; return TRUE; }
if (checkPos(4, i + 1, field)) { *x = 4; *y = i+1; return TRUE; }
if (checkPos(i - 1, i + 1, field)) { *x = i-1; *y = i+1; return TRUE; }
if (checkPos(i + 1, i - 1, field)) { *x = i+1; *y = i-1; return TRUE; }
if (checkPos(i + 1, 4, field)) { *x = i+1; *y = 4; return TRUE; }
if (checkPos(i - 1, 2, field)) { *x = i-1; *y = 2; return TRUE; }
}
return FALSE;
}
printBoard(brd, name)
intBoard brd;
char *name;
{
short x, y;
printf( "%s\n", name );
for (y = 0; y <= 18; y++)
{
for (x = 0; x <= 18; x++)
printf("%d ", brd[x][y]);
printf("\n");
}
}
short noNbrs( x, y )
short x, y;
{
if (x > 0 && bord[x-1][y] != 0) return FALSE;
if (x < 18 && bord[x+1][y] != 0) return FALSE;
if (y > 0 && bord[x][y-1] != 0) return FALSE;
if (y < 18 && bord[x][y+1] != 0) return FALSE;
return TRUE;
}
short extend(x, y)
short *x, *y;
{
short i;
playReason = "extend";
for (i = 2; i <= 18-2; i++)
if (claim[2][i] == 0 && noNbrs( 2, i ))
{
*x = 2;
*y = i;
return TRUE;
}
for (i = 2; i <= 18-2; i++)
if (claim[i][18-2] == 0 && noNbrs( 2, i ))
{
*x = i;
*y = 18-2;
return TRUE;
}
for (i = 18-2; i >= 2; i--)
if (claim[18-2][i] == 0 && noNbrs( 18-2, i ))
{
*x = 18-2;
*y = i;
return TRUE;
}
for (i = 18-2; i >= 2; i--)
if (claim[i][2] == 0 && noNbrs( i, 2 ))
{
*x = i;
*y = 2;
return TRUE;
}
return FALSE;
}
short extend2( x, y )
short *x, *y;
{
short i, lowest = BIGGEST, value;
playReason = "extend2";
for (i = 3; i <= 18-3; i++)
if (legal[2][i]) /* if there is nobody there */
{
value = claim[2][i]; /* get influence */
if ((value < 7) && /* a reasonable hole in my wall */
(value > -5) && /* or a reasonable gap in his */
(bord[2][i + 1] == 0) && /* not in contact with any stones */
(bord[2][i - 1] == 0))
if (value < lowest)
{
lowest = value; /* lowest gets the smallest value */
*x = 2; /* that was seen along all the 3-lines */
*y = i; /* x and y save that location */
}
}
for (i = 3; i <= 18-3; i++)
if (legal[i][2])
{
value = claim[i][2];
if ((value < 7) &&
(value > -5) &&
(bord[i + 1][2] == 0) &&
(bord[i - 1][2] == 0))
if (value < lowest)
{
lowest = value;
*x = i;
*y = 2;
}
}
for (i = 18-3; i >= 3; i--)
if (legal[18 - 2][i])
{
value = claim[18 - 2][i];
if ((value < 7) &&
(value > -5) &&
(bord[18 - 2][i + 1] == 0) &&
(bord[18 - 2][i - 1] == 0))
if (value < lowest)
{
lowest = value;
*x = 18 - 2;
*y = i;
}
}
for (i = 3; i <= 18-3; i++)
if (legal[i][18 - 2])
{
value = claim[i][18 - 2];
if ((value < 7) &&
(value > -5) &&
(bord[i + 1][18 - 2] == 0) &&
(bord[i - 1][18 - 2] == 0))
if (value < lowest)
{
lowest = value;
*x = i;
*y = 18 - 2;
}
}
if (lowest == BIGGEST) return FALSE;
return TRUE;
}
/*
check to see if I can save anything in atari
*/
short lookForSave(x, y)
short *x, *y;
{ /* lookForSave */
short i;
playReason = "lookForSave";
for (i = 1; i <= maxGroupID; i++) /* scan the group list */
if ((gList[i].libC == 1) &&
(ndbord[gList[i].lx][gList[i].ly] == 1))
if (saveable(gList[i].lx, gList[i].ly, x, y)) /* see if I can save it */
return TRUE;
return FALSE;
} /* lookForSave */
/*
check to see if I can save anything with n libs
*/
short lookForSaveN(x, y)
short *x, *y;
{ /* lookForSaveN */
short i;
if (saveNLibs)
{
playReason = "lookForSaveN";
for (i = 1; i <= maxGroupID; i++) /* scan the group list */
if ((gList[i].libC > 1) &&
(gList[i].libC <= treeLibLim) &&
(ndbord[gList[i].lx][gList[i].ly] == 1))
{
if (killable(gList[i].lx, gList[i].ly, x, y))
if (saveable(gList[i].lx, gList[i].ly, x, y)) /* see if I can save it */
return TRUE;
}
}
return FALSE;
} /* lookForSaveN */
/*
check to see if I can kill anything
*/
short lookForKill(x, y)
short *x, *y;
{ /* lookForKill */
short i;
playReason = "lookForKill";
for (i = 1; i <= maxGroupID; i++) /* scan the group list */
if ((gList[i].libC == 1) &&
(ndbord[gList[i].lx][gList[i].ly] == -1))
{ /* we found a live enemy group with one liberty */
spanGroup(gList[i].lx, gList[i].ly, &pList); /* find the liberty */
*x = pList.p[1].px;
*y = pList.p[1].py;
if (legal[*x][*y])
return TRUE;
}
return FALSE;
} /* lookForKill */
short doubleAtari(x, y)
short *x, *y;
{ /* doubleAtari */
short i, j;
playReason = "doubleAtari";
for (i = 1; i <= maxGroupID - 1; i++)
if ((gList[i].libC == 2) &&
(ndbord[gList[i].lx][gList[i].ly] == -1)) /* found an atariable group of his */
{
spanGroup(gList[i].lx, gList[i].ly, &dapList1);
for (j = i + 1; j <= maxGroupID; j++)
if ((gList[j].libC == 2) &&
(ndbord[gList[j].lx][gList[j].ly] == -1))
{
spanGroup(gList[j].lx, gList[j].ly, &dapList2);
intersectPlist(&dapList1, &dapList2, &dapList3);
if (dapList3.indx > 0)
if (legal[dapList3.p[1].px][dapList3.p[1].py])
{
tryPlay(dapList3.p[1].px, dapList3.p[1].py, 1);
if (gList[groupIDs[dapList3.p[1].px][
dapList3.p[1].py]].libC > 1)
{
*x = dapList3.p[1].px;
*y = dapList3.p[1].py;
restoreState();
return TRUE;
}
restoreState();
}
}
}
return FALSE;
} /* doubleAtari */
short lookForAttack(x, y)
short *x, *y;
{ /* lookForAttack */
short tx, ty, i;
playReason = "lookForAttack";
for (i = 1; i <= maxGroupID; i++) /* scan the group list */
if ((! gList[i].isLive) &&
(gList[i].libC > 1) &&
(gList[i].libC <= (treeLibLim + 1)) &&
(ndbord[gList[i].lx][gList[i].ly] == -1))
{
if (killable(gList[i].lx, gList[i].ly, &tx, &ty)) /* can we kill it? */
{
*x = tx; /* yep - do so */
*y = ty;
return TRUE;
}
}
return FALSE;
} /* lookForAttack */
/*
Plays a move that requires a response on the opponent's part
*/
short threaten(x, y)
short *x, *y;
{ /* threaten */
short i, j, gx, gy, tNum;
playReason = "threaten";
initArray(threatBord);
for (i = 1; i <= maxGroupID; i++)
if ((! gList[i].isLive) &&
(ndbord[gList[i].lx][gList[i].ly] == -1))
{
spanGroup(gList[i].lx, gList[i].ly, &pList);
for (j = 1; j <= pList.indx; j++)
if (legal[pList.p[j].px][pList.p[j].py])
{
tryPlay(pList.p[j].px, pList.p[j].py, 1);
if (gList[groupIDs[pList.p[j].px][pList.p[j].py]].libC > 1)
if (killable(gList[i].lx, gList[i].ly, &gx, &gy))
threatBord[pList.p[j].px][pList.p[j].py] += 1;
restoreState();
}
}
tNum = 0;
for (i = 0; i <= maxPoint; i++)
for (j = 0; j <= maxPoint; j++)
if ((threatBord[i][j] > tNum) &&
((threatBord[i][j] > 1) ||
(connectMap[i][j] > 0)))
{
tNum = threatBord[i][j];
*x = i;
*y = j;
}
if (tNum > 0) return TRUE;
else return FALSE;
} /* threaten */
/*
connects against enemy cuts
*/
short connectCut(x, y)
short *x, *y;
{ /* connectCut */
short i, j, nap, gid, infl;
playReason = "connectCut";
for (i = 0; i <= maxPoint; i++)
for (j = 0; j <= maxPoint; j++)
if (legal[i][j] &&
(protPoints[i][j] == 0)) /* not a protected point */
{
nap = 0; /* how many of my stones am I adjacent to? */
if ((i > 0) && (bord[i - 1][j] == 1))
{
nap = nap + 1;
pList.p[nap].px = i - 1;
pList.p[nap].py = j;
}
if ((j > 0) && (bord[i][j - 1] == 1))
{
nap = nap + 1;
pList.p[nap].px = i;
pList.p[nap].py = j - 1;
}
if ((i < maxPoint) && (bord[i + 1][j] == 1))
{
nap = nap + 1;
pList.p[nap].px = i + 1;
pList.p[nap].py = j;
}
if ((j < maxPoint) && (bord[i][j + 1] == 1))
{
nap = nap + 1;
pList.p[nap].px = i;
pList.p[nap].py = j + 1;
}
if (nap == 1) /* possible knight's || 2-point extention */
{
gid = groupIDs[pList.p[1].px][pList.p[1].py];
if ((i > 0) && (i < maxPoint) &&
(ndbord[i - 1][j] == 1) &&
(ndbord[i + 1][j] == 0)) /* contact on left */
{
if (((j > 0) && (ndbord[i][j - 1] == -1) &&
(ndbord[i + 1][j - 1] == 1) &&
(gid != groupIDs[i + 1][j - 1])) ||
((j < maxPoint) && (ndbord[i][j + 1] == -1) &&
(ndbord[i + 1][j + 1] == 1) &&
(gid != groupIDs[i + 1][j + 1])) ||
((((j > 0) && (ndbord[i][j - 1] == -1)) ||
((j < maxPoint) && (ndbord[i][j + 1] == -1))) &&
(i < (maxPoint - 1)) &&
(ndbord[i + 2][j] == 1) &&
(gid != groupIDs[i + 2][j])))
{
*x = i;
*y = j;
if (safeMove(*x, *y))
return TRUE;
}
}
else if ((i < maxPoint) && (i > 0) &&
(ndbord[i + 1][j] == 1) &&
(ndbord[i - 1][j] == 0)) /* r */
{
if (((j > 0) && (ndbord[i][j - 1] == -1) &&
(ndbord[i - 1][j - 1] == 1) &&
(gid != groupIDs[i - 1][j - 1])) ||
((j < maxPoint) && (ndbord[i][j + 1] == -1) &&
(ndbord[i - 1][j + 1] == 1) &&
(gid != groupIDs[i - 1][j + 1])) ||
((((j > 0) && (ndbord[i][j - 1] == -1)) ||
((j < maxPoint) && (ndbord[i][j + 1] == -1))) &&
(i > 1) &&
(ndbord[i - 2][j] == 1) &&
(gid != groupIDs[i - 2][j])))
{
*x = i;
*y = j;
if (safeMove(*x, *y))
return TRUE;
}
}
else if ((j > 0) && (j < maxPoint) &&
(ndbord[i][j - 1] == 1) &&
(ndbord[i][j + 1] == 0)) /* top */
{
if (((i > 0) && (ndbord[i - 1][j] == -1) &&
(ndbord[i - 1][j + 1] == 1) &&
(gid != groupIDs[i - 1][j + 1])) ||
((i < maxPoint) && (ndbord[i + 1][j] == -1) &&
(ndbord[i + 1][j + 1] == 1) &&
(gid != groupIDs[i + 1][j + 1])) ||
((((i > 0) && (ndbord[i - 1][j] == -1)) ||
((i < maxPoint) && (ndbord[i + 1][j] == -1))) &&
(j < (maxPoint - 1)) &&
(ndbord[i][j + 2] == 1) &&
(gid != groupIDs[i][j + 2])))
{
*x = i;
*y = j;
if (safeMove(*x, *y))
return TRUE;
}
}
else if ((j > 0) && (j < maxPoint) &&
(ndbord[i][j + 1] == 1) &&
(ndbord[i][j - 1] == 0)) /* bottom */
{
if (((i > 0) && (ndbord[i - 1][j] == -1) &&
(ndbord[i - 1][j - 1] == 1) &&
(gid != groupIDs[i - 1][j - 1])) ||
((i < maxPoint) && (ndbord[i + 1][j] == -1) &&
(ndbord[i + 1][j - 1] == 1) &&
(gid != groupIDs[i + 1][j - 1])) ||
((((i > 0) && (ndbord[i - 1][j] == -1)) ||
((i < maxPoint) && (ndbord[i + 1][j] == -1))) &&
(j > 1) &&
(ndbord[i][j - 2] == 1) &&
(gid != groupIDs[i][j - 2])))
{
*x = i;
*y = j;
if (safeMove(*x, *y))
return TRUE;
}
}
}
else if (nap == 2) /* diagonal or 1-point extention */
{
if (groupIDs[pList.p[1].px][pList.p[1].py] !=
groupIDs[pList.p[2].px][pList.p[2].py])
{
if ((pList.p[1].px != pList.p[2].px) &&
(pList.p[1].py != pList.p[2].py)) /* diag */
{
spanGroup(pList.p[1].px,
pList.p[1].py, &pList1);
spanGroup(pList.p[2].px,
pList.p[2].py, &plist2);
intersectPlist(&pList1, &plist2, &plist3);
if (plist3.indx == 1)
if ((i > 0) && (ndbord[i - 1][j] == -1) ||
(i < maxPoint) && (ndbord[i + 1][j] == -1) ||
(j > 0) && (ndbord[i][j - 1] == -1) ||
(j < maxPoint) && (ndbord[i][j + 1] == -1))
{ /* must make direct connection */
*x = i;
*y = j;
if (heCanCut(*x, *y))
if (safeMove(*x, *y))
return TRUE;
}
else if (heCanCut(i, j))
{ /* protect point if possible */
infl = 1000;
if ((i > 0) && legal[i - 1][j] &&
((i == 1) || (ndbord[i - 2][j] == 0)) &&
((j == 0) || (ndbord[i - 1][j - 1] == 0)) &&
((j == maxPoint) ||
(ndbord[i - 1][j + 1] == 0)))
if (safeMove(i - 1, j))
if (claim[i - 1][j] < infl)
{
*x = i - 1;
*y = j;
infl = claim[i - 1][j];
}
if ((j > 0) && legal[i][j - 1] &&
((j == 1) || (ndbord[i][j - 2] == 0)) &&
((i == 0) || (ndbord[i - 1][j - 1] == 0)) &&
((i == maxPoint) ||
(ndbord[i + 1][j - 1] == 0)))
if (safeMove(i, j - 1))
if (claim[i][j - 1] < infl)
{
*x = i;
*y = j - 1;
infl = claim[i][j - 1];
}
if ((i < maxPoint) && legal[i + 1][j] &&
((i == (maxPoint - 1)) ||
(ndbord[i + 2][j] == 0)) &&
((j == 0) || (ndbord[i + 1][j - 1] == 0)) &&
((j == maxPoint) ||
(ndbord[i + 1][j + 1] == 0)))
if (safeMove(i + 1, j))
if (claim[i + 1][j] < infl)
{
*x = i + 1;
*y = j;
infl = claim[i + 1][j];
}
if ((j < maxPoint) && legal[i][j + 1] &&
((j == (maxPoint - 1)) ||
(ndbord[i][j + 2] == 0)) &&
((i == 0) || (ndbord[i - 1][j + 1] == 0)) &&
((i == maxPoint) ||
(ndbord[i + 1][j + 1] == 0)))
if (safeMove(i, j + 1))
if (claim[i][j + 1] < infl)
{
*x = i;
*y = j + 1;
infl = claim[i][j + 1];
}
if (infl < 1000)
return TRUE;
*x = i; /* direct connection */
*y = j;
if (safeMove(*x, *y))
return TRUE;
}
}
else /* 1-point extension, only protect if threatened */
{
if ((i > 0) && (ndbord[i - 1][j] == -1) ||
(j > 0) && (ndbord[i][j - 1] == -1) ||
(i < maxPoint) && (ndbord[i + 1][j] == -1) ||
(j < maxPoint) && (ndbord[i][j + 1] == -1))
{
*x = i;
*y = j;
if (heCanCut(*x, *y))
if (safeMove(*x, *y))
return TRUE;
}
}
}
}
else if (nap == 3) /* unprotected, but me on 3 sides */
{
if ((groupIDs[pList.p[1].px][pList.p[1].py] !=
groupIDs[pList.p[2].px][pList.p[2].py]) ||
(groupIDs[pList.p[1].px][pList.p[1].py] !=
groupIDs[pList.p[3].px][pList.p[3].py]) ||
(groupIDs[pList.p[3].px][pList.p[3].py] !=
groupIDs[pList.p[2].px][pList.p[2].py]))
{
spanGroup(pList.p[1].px, pList.p[1].py, &pList1);
spanGroup(pList.p[2].px, pList.p[2].py, &plist2);
intersectPlist(&pList1, &plist2, &plist3);
spanGroup(pList.p[3].px, pList.p[3].py, &plist2);
intersectPlist(&plist2, &plist3, &pList1);
if (pList1.indx == 1) /* a common connect point */
if (heCanCut(i, j))
if (safeMove(i, j))
{
*x = i;
*y = j;
return TRUE;
}
}
}
}
return FALSE;
} /* connectCut */
short heCanCut(x, y)
short x, y;
{ /* heCanCut */
short gx, gy, result;
if (playLevel > 3)
{
tryPlay(x, y, -1); /* try his cut */
result = ! killable(x, y, &gx, &gy);
restoreState();
return result;
}
else
return FALSE;
} /* heCanCut */
/*
Checks out a move.
If my stone is not killable then true.
*/
short safeMove(x, y)
short x, y;
{ /* safeMove */
short gbx, gby, result;
tryPlay(x, y, 1); /* try playing at point */
if (killFlag) /* I shouldn't kill if lookForKill didn't */
result = FALSE;
else if (gList[groupIDs[x][y]].libC < 2)
{ /* if it is in atari or dead */
result = FALSE; /* reject it */
}
else if (gList[groupIDs[x][y]].libC <= treeLibLim) /* see if killable */
if (playLevel > 0)
result = ! killable(x, y, &gbx, &gby);
else
result = TRUE;
else
result = TRUE;
restoreState();
return result;
} /* safeMove */
/*
Extends walls in a connected fashion.
Finds the lowest influence (mine) point that is connected to one
of my groups.
Only looks in the center of the board.
*/
short extendWall(x, y)
short *x, *y;
{ /* extendWall */
short infl, i, j;
playReason = "extendWall";
*x = iNil;
*y = iNil;
infl = 11;
for (i = 2; i <= maxPoint - 2; i++)
for (j = 2; j <= maxPoint - 2; j++)
if (legal[i][j])
if (connectMap[i][j] > 0)
if ((claim[i][j] < infl) &&
(ndbord[i - 1][j] < 1) &&
(ndbord[i + 1][j] < 1) &&
(ndbord[i][j - 1] < 1) &&
(ndbord[i][j + 1] < 1) &&
((claim[i - 1][j] < 0) ||
(claim[i + 1][j] < 0) ||
(claim[i][j - 1] < 0) ||
(claim[i][j + 1] < 0)))
if (safeMove(i, j))
{
infl = claim[i][j];
*x = i;
*y = j;
}
if (*x != iNil) return TRUE;
return FALSE;
} /* extendWall */
/*
check to see if I can attack one of his groups
uses limited depth search so that it can work on larger lib counts
*/
short findAttack2(x, y)
short *x, *y;
{ /* findAttack2 */
short tx, ty, i, otll;
if (playLevel < 7)
return FALSE;
playReason = "findAttack2";
depthLimit = 8;
otll = treeLibLim;
for (i = 1; i <= maxGroupID; i++) /* scan the group list */
if ((! gList[i].isLive) &&
(ndbord[gList[i].lx][gList[i].ly] == -1) &&
(gList[i].libC > 1))
{
treeLibLim = 6;
if (killable(gList[i].lx, gList[i].ly, &tx, &ty)) /* can we kill it? */
{
*x = tx; /* yep - do so */
*y = ty;
return TRUE;
}
treeLibLim = otll;
}
depthLimit = 100;
return FALSE;
} /* findAttack2 */
/*
blocks enemy cuts thru 1-point extensions
*/
short blockCut(x, y)
short *x, *y;
{ /* blockCut */
short i, j;
playReason = "blockCut";
for (i = 0; i <= maxPoint; i++)
for (j = 0; j <= maxPoint; j++)
if (legal[i][j])
{
if ((i > 0) && (j > 0) && (j < maxPoint))
{
if ((ndbord[i - 1][j] == -1) &&
(ndbord[i - 1][j - 1] == 1) &&
(ndbord[i - 1][j + 1] == 1) &&
(groupIDs[i - 1][j - 1] != groupIDs[i - 1][j + 1]))
{
*x = i;
*y = j;
if (heCanCut(*x, *y))
if (safeMove(*x, *y))
return TRUE;
}
}
if ((i < maxPoint) && (j > 0) && (j < maxPoint))
{
if ((ndbord[i + 1][j] == -1) &&
(ndbord[i + 1][j - 1] == 1) &&
(ndbord[i + 1][j + 1] == 1) &&
(groupIDs[i + 1][j - 1] != groupIDs[i + 1][j + 1]))
{
*x = i;
*y = j;
if (heCanCut(*x, *y))
if (safeMove(*x, *y))
return TRUE;
}
}
if ((j > 0) && (i > 0) && (i < maxPoint))
{
if ((ndbord[i][j - 1] == -1) &&
(ndbord[i - 1][j - 1] == 1) &&
(ndbord[i + 1][j - 1] == 1) &&
(groupIDs[i - 1][j - 1] != groupIDs[i + 1][j - 1]))
{
*x = i;
*y = j;
if (heCanCut(*x, *y))
if (safeMove(*x, *y))
return TRUE;
}
}
if ((j < maxPoint) && (i > 0) && (i < maxPoint))
{
if ((ndbord[i][j + 1] == -1) &&
(ndbord[i - 1][j + 1] == 1) &&
(ndbord[i + 1][j + 1] == 1) &&
(groupIDs[i - 1][j + 1] != groupIDs[i + 1][j + 1]))
{
*x = i;
*y = j;
if (heCanCut(*x, *y))
if (safeMove(*x, *y))
return TRUE;
}
}
}
return FALSE;
} /* blockCut */
/*
cuts the enemy
*/
short cutHim(x, y)
short *x, *y;
{ /* cutHim */
short i, j, nap, gid;
playReason = "cutHim";
for (i = 0; i <= maxPoint; i++)
for (j = 0; j <= maxPoint; j++)
if (legal[i][j])
{
nap = 0; /* how many of his stones am I adjacent to? */
if ((i > 0) && (ndbord[i - 1][j] == -1))
{
nap = nap + 1;
pList.p[nap].px = i - 1;
pList.p[nap].py = j;
}
if ((j > 0) && (ndbord[i][j - 1] == -1))
{
nap = nap + 1;
pList.p[nap].px = i;
pList.p[nap].py = j - 1;
}
if ((i < maxPoint) && (ndbord[i + 1][j] == -1))
{
nap = nap + 1;
pList.p[nap].px = i + 1;
pList.p[nap].py = j;
}
if ((j < maxPoint) && (ndbord[i][j + 1] == -1))
{
nap = nap + 1;
pList.p[nap].px = i;
pList.p[nap].py = j + 1;
}
if (nap == 1) /* possible knight's or 2-point extention */
{
gid = groupIDs[pList.p[1].px][pList.p[1].py];
if ((i > 0) && (i < maxPoint) &&
(ndbord[i - 1][j] == -1) &&
(connectMap[i][j] > 0)) /* contact on left */
{
if (((j > 0) &&
(ndbord[i + 1][j - 1] == -1) &&
(gid != groupIDs[i + 1][j - 1])) ||
((j < maxPoint) &&
(ndbord[i + 1][j + 1] == -1) &&
(gid != groupIDs[i + 1][j + 1])) ||
((i < (maxPoint - 1)) &&
(ndbord[i + 1][j] == 0) &&
(ndbord[i + 2][j] == -1) &&
(gid != groupIDs[i + 2][j])))
{
*x = i;
*y = j;
if (safeMove(*x, *y))
return TRUE;
}
}
else if ((i < maxPoint) && (i > 0) &&
(ndbord[i + 1][j] == -1) &&
(connectMap[i][j] > 0)) /* r */
{
if (((j > 0) &&
(ndbord[i - 1][j - 1] == -1) &&
(gid != groupIDs[i - 1][j - 1])) ||
((j < maxPoint) &&
(ndbord[i - 1][j + 1] == -1) &&
(gid != groupIDs[i - 1][j + 1])) ||
((i > 1) &&
(ndbord[i - 1][j] == 0) &&
(ndbord[i - 2][j] == -1) &&
(gid != groupIDs[i - 2][j])))
{
*x = i;
*y = j;
if (safeMove(*x, *y))
return TRUE;
}
}
else if ((j > 0) && (j < maxPoint) &&
(ndbord[i][j - 1] == -1) &&
(connectMap[i][j] > 0)) /* top */
{
if (((i > 0) &&
(ndbord[i - 1][j + 1] == -1) &&
(gid != groupIDs[i - 1][j + 1])) ||
((i < maxPoint) &&
(ndbord[i + 1][j + 1] == -1) &&
(gid != groupIDs[i + 1][j + 1])) ||
((j < (maxPoint - 1)) &&
(ndbord[i][j + 1] == 0) &&
(ndbord[i][j + 2] == -1) &&
(gid != groupIDs[i][j + 2])))
{
*x = i;
*y = j;
if (safeMove(*x, *y))
return TRUE;
}
}
else if ((j > 0) && (j < maxPoint) &&
(ndbord[i][j + 1] == -1) &&
(connectMap[i][j] > 0)) /* bottom */
{
if (((i > 0) &&
(ndbord[i - 1][j - 1] == -1) &&
(gid != groupIDs[i - 1][j - 1])) ||
((i < maxPoint) &&
(ndbord[i + 1][j - 1] == -1) &&
(gid != groupIDs[i + 1][j - 1])) ||
((j > 1) &&
(ndbord[i][j - 1] == 0) &&
(ndbord[i][j - 2] == -1) &&
(gid != groupIDs[i][j - 2])))
{
*x = i;
*y = j;
if (safeMove(*x, *y))
return TRUE;
}
}
}
else if (nap == 2) /* diagonal or 1-point extention */
{
if (groupIDs[pList.p[1].px][pList.p[1].py] !=
groupIDs[pList.p[2].px][pList.p[2].py])
{
if ((pList.p[1].px != pList.p[2].px) &&
(pList.p[1].py != pList.p[2].py)) /* diag */
{
spanGroup(pList.p[1].px,
pList.p[1].py, &pList1);
spanGroup(pList.p[2].px,
pList.p[2].py, &plist2);
intersectPlist(&pList1, &plist2, &plist3);
if (plist3.indx == 1)
{
*x = i;
*y = j;
if (safeMove(*x, *y))
return TRUE;
}
}
else /* 1-point extension, only cut if connected */
{
if (connectMap[i][j] > 0)
{
*x = i;
*y = j;
if (safeMove(*x, *y))
return TRUE;
}
}
}
}
else if (nap == 3) /* unprotected, but him on 3 sides */
{
if ((groupIDs[pList.p[1].px][pList.p[1].py] !=
groupIDs[pList.p[2].px][pList.p[2].py]) ||
(groupIDs[pList.p[1].px][pList.p[1].py] !=
groupIDs[pList.p[3].px][pList.p[3].py]) ||
(groupIDs[pList.p[3].px][pList.p[3].py] !=
groupIDs[pList.p[2].px][pList.p[2].py]))
{
spanGroup(pList.p[1].px, pList.p[1].py, &pList1);
spanGroup(pList.p[2].px, pList.p[2].py, &plist2);
intersectPlist(&pList1, &plist2, &plist3);
spanGroup(pList.p[3].px, pList.p[3].py, &plist2);
intersectPlist(&plist2, &plist3, &pList1);
if (pList1.indx == 1) /* a common connect point */
if (safeMove(i, j))
{
*x = i;
*y = j;
return TRUE;
}
}
}
}
return FALSE;
} /* cutHim */
/*
ataris a group just for the hell of it
*/
short atariAnyway(x, y)
short *x, *y;
{ /* atariAnyway */
short i;
playReason = "atariAnyway";
for (i = 1; i <= maxGroupID; i++) /* scan the group list */
if ((gList[i].libC == 2) &&
(ndbord[gList[i].lx][gList[i].ly] == -1))
{
spanGroup(gList[i].lx, gList[i].ly, &pList);
if (legal[pList.p[1].px][pList.p[1].py] &&
((connectMap[pList.p[1].px][pList.p[1].py] > 0) ||
((pList.p[1].px > 0) &&
(connectMap[pList.p[1].px - 1][pList.p[1].py] > 0)) ||
((pList.p[1].px < maxPoint) &&
(connectMap[pList.p[1].px + 1][pList.p[1].py] > 0)) ||
((pList.p[1].py > 0) &&
(connectMap[pList.p[1].px][pList.p[1].py - 1] > 0)) ||
((pList.p[1].py < maxPoint) &&
(connectMap[pList.p[1].px][pList.p[1].py + 1] > 0))))
if (safeMove(pList.p[1].px, pList.p[1].py))
{
*x = pList.p[1].px;
*y = pList.p[1].py;
return TRUE;
}
if (legal[pList.p[2].px][pList.p[2].py] &&
((connectMap[pList.p[2].px][pList.p[2].py] > 0) ||
((pList.p[2].px > 0) &&
(connectMap[pList.p[2].px - 1][pList.p[2].py] > 0)) ||
((pList.p[2].px < maxPoint) &&
(connectMap[pList.p[2].px + 1][pList.p[2].py] > 0)) ||
((pList.p[2].py > 0) &&
(connectMap[pList.p[2].px][pList.p[2].py - 1] > 0)) ||
((pList.p[2].py < maxPoint) &&
(connectMap[pList.p[2].px][pList.p[2].py + 1] > 0))))
if (safeMove(pList.p[2].px, pList.p[2].py))
{
*x = pList.p[2].px;
*y = pList.p[2].py;
return TRUE;
}
}
return FALSE;
} /* atariAnyway */
/*
undercuts his groups
*/
short underCut(x, y)
short *x, *y;
{ /* underCut */
short i, j;
playReason = "underCut";
for (i = 1; i <= maxPoint - 1; i++)
{
if (legal[0][i])
{
if (ndbord[1][i] == -1)
if (safeMove(0, i))
{
*x = 0;
*y = i;
return TRUE;
}
}
if (legal[maxPoint][i])
{
if (ndbord[maxPoint - 1][i] == -1)
if (safeMove(maxPoint, i))
{
*x = maxPoint;
*y = i;
return TRUE;
}
}
if (legal[i][0])
{
if (ndbord[i][1] == -1)
if (safeMove(i, 0))
{
*x = i;
*y = 0;
return TRUE;
}
}
if (legal[i][maxPoint])
{
if (ndbord[i][maxPoint - 1] == -1)
if (safeMove(i, maxPoint))
{
*x = i;
*y = maxPoint;
return TRUE;
}
}
}
return FALSE;
} /* underCut */
/*
drops to the edge of the board if threatened
*/
short dropToEdge(x, y)
short *x, *y;
{ /* dropToEdge */
short i;
playReason = "dropToEdge";
for (i = 1; i <= maxPoint - 1; i++)
{
if (legal[1][i])
if ((ndbord[2][i] == 1) &&
(ndbord[0][i] == 0) &&
(ndbord[1][i - 1] < 1) &&
(ndbord[1][i + 1] < 1) &&
((ndbord[2][i - 1] == -1) ||
(ndbord[2][i + 1] == -1) ||
(ndbord[1][i - 1] == -1) ||
(ndbord[1][i + 1] == -1)))
{
*x = 1;
*y = i;
if (safeMove(*x, *y))
return TRUE;
}
if (legal[maxPoint - 1][i])
if ((ndbord[maxPoint - 2][i] == 1) &&
(ndbord[maxPoint][i] == 0) &&
(ndbord[maxPoint - 1][i - 1] < 1) &&
(ndbord[maxPoint - 1][i + 1] < 1) &&
((ndbord[maxPoint - 2][i - 1] == -1) ||
(ndbord[maxPoint - 2][i + 1] == -1) ||
(ndbord[maxPoint - 1][i - 1] == -1) ||
(ndbord[maxPoint - 1][i + 1] == -1)))
{
*x = maxPoint - 1;
*y = i;
if (safeMove(*x, *y))
return TRUE;
}
if (legal[i][1])
if ((ndbord[i][2] == 1) &&
(ndbord[i][0] == 0) &&
(ndbord[i - 1][1] < 1) &&
(ndbord[i + 1][1] < 1) &&
((ndbord[i - 1][2] == -1) ||
(ndbord[i + 1][2] == -1) ||
(ndbord[i - 1][1] == -1) ||
(ndbord[i + 1][1] == -1)))
{
*x = i;
*y = 1;
if (safeMove(*x, *y))
return TRUE;
}
if (legal[i][maxPoint - 1])
if ((ndbord[i][maxPoint - 2] == 1) &&
(ndbord[i][maxPoint] == 0) &&
(ndbord[i - 1][maxPoint - 1] < 1) &&
(ndbord[i + 1][maxPoint - 1] < 1) &&
((ndbord[i - 1][maxPoint - 2] == -1) ||
(ndbord[i + 1][maxPoint - 2] == -1) ||
(ndbord[i - 1][maxPoint - 1] == -1) ||
(ndbord[i + 1][maxPoint - 1] == -1)))
{
*x = i;
*y = maxPoint - 1;
if (safeMove(*x, *y))
return TRUE;
}
if (legal[0][i])
if ((ndbord[1][i] == 1) &&
(ndbord[0][i - 1] < 1) &&
(ndbord[0][i + 1] < 1) &&
(((ndbord[1][i - 1] == -1) &&
(ndbord[1][i + 1] == -1)) ||
(ndbord[0][i - 1] == -1) ||
(ndbord[0][i + 1] == -1)))
{
*x = 0;
*y = i;
if (safeMove(*x, *y))
return TRUE;
}
if (legal[maxPoint][i])
if ((ndbord[maxPoint - 1][i] == 1) &&
(ndbord[maxPoint][i - 1] < 1) &&
(ndbord[maxPoint][i + 1] < 1) &&
(((ndbord[maxPoint - 1][i - 1] == -1) &&
(ndbord[maxPoint - 1][i + 1] == -1)) ||
(ndbord[maxPoint][i - 1] == -1) ||
(ndbord[maxPoint][i + 1] == -1)))
{
*x = maxPoint;
*y = i;
if (safeMove(*x, *y))
return TRUE;
}
if (legal[i][0])
if ((ndbord[i][1] == 1) &&
(ndbord[i - 1][0] < 1) &&
(ndbord[i + 1][0] < 1) &&
(((ndbord[i - 1][1] == -1) &&
(ndbord[i + 1][1] == -1)) ||
(ndbord[i - 1][0] == -1) ||
(ndbord[i + 1][0] == -1)))
{
*x = i;
*y = 0;
if (safeMove(*x, *y))
return TRUE;
}
if (legal[i][maxPoint])
if ((ndbord[i][maxPoint - 1] == 1) &&
(ndbord[i - 1][maxPoint] < 1) &&
(ndbord[i + 1][maxPoint] < 1) &&
(((ndbord[i - 1][maxPoint - 1] == -1) &&
(ndbord[i + 1][maxPoint - 1] == -1)) ||
(ndbord[i - 1][maxPoint] == -1) ||
(ndbord[i + 1][maxPoint] == -1)))
{
*x = i;
*y = maxPoint;
if (safeMove(*x, *y))
return TRUE;
}
}
return FALSE;
} /* dropToEdge */
/*
Pushes walls in a tightly connected fashion.
Finds the lowest influence (mine) point that is connected to one
of my groups.
*/
short pushWall(x, y)
short *x, *y;
{ /* pushWall */
short infl, i, j, na;
playReason = "pushWall";
*x = iNil;
*y = iNil;
infl = 11;
for (i = 0; i <= maxPoint; i++)
for (j = 0; j <= maxPoint; j++)
if (legal[i][j])
if (connectMap[i][j] > 0)
if ((claim[i][j] < infl) &&
(((i > 0) && (ndbord[i - 1][j] == 1)) ||
((i < maxPoint) && (ndbord[i + 1][j] == 1)) ||
((j > 0) && (ndbord[i][j - 1] == 1)) ||
((j < maxPoint) && (ndbord[i][j + 1] == 1)) ||
((i > 0) && (j > 0) && (ndbord[i - 1][j - 1] == 1)) ||
((i < maxPoint) && (j > 0) && (ndbord[i + 1][j - 1] == 1)) ||
((i > 0) && (j < maxPoint) && (ndbord[i - 1][j + 1] == 1)) ||
((i < maxPoint) && (j < maxPoint) &&
(ndbord[i + 1][j + 1] == 1))) &&
(((i > 0) && (claim[i - 1][j] < 0)) ||
((i < maxPoint) && (claim[i + 1][j] < 0)) ||
((j > 0) && (claim[i][j - 1] < 0)) ||
((j < maxPoint) && (claim[i][j + 1] < 0))))
{
na = 0;
if ((i > 0) && (ndbord[i - 1][j] != 0))
na = na + 1;
if ((i < maxPoint) && (ndbord[i + 1][j] != 0))
na = na + 1;
if ((j > 0) && (ndbord[i][j - 1] != 0))
na = na + 1;
if ((j < maxPoint) && (ndbord[i][j + 1] != 0))
na = na + 1;
if (na < 3)
if (safeMove(i, j))
{
infl = claim[i][j];
*x = i;
*y = j;
}
}
if (*x != iNil) return TRUE;
return FALSE;
} /* pushWall */
/*
reduces the liberty count of one of his groups
*/
short reduceHisLiberties(x, y)
short *x, *y;
{ /* reduceHisLiberties */
short i, j;
playReason = "reduceHisLiberties";
sortLibs();
for (i = 1; i <= maxGroupID; i++)
if ((! gList[sGlist[i]].isLive) &&
(gList[sGlist[i]].libC > 2) &&
(ndbord[gList[sGlist[i]].lx][gList[sGlist[i]].ly] == -1))
{
spanGroup(gList[sGlist[i]].lx, gList[sGlist[i]].ly, &pList);
for (j = 1; j <= pList.indx; j++)
if (legal[pList.p[j].px][pList.p[j].py] &&
(connectMap[pList.p[j].px][pList.p[j].py] > 0))
if (safeMove(pList.p[j].px, pList.p[j].py))
{
*x = pList.p[j].px;
*y = pList.p[j].py;
return TRUE;
}
}
return FALSE;
} /* reduceHisLiberties */
/*
connects a group to the edge
*/
short dropToEdge2(x, y)
short *x, *y;
{ /* dropToEdge2 */
short i;
playReason = "dropToEdge2";
for (i = 1; i <= maxPoint - 1; i++)
{
if (legal[i][0])
{
if ((ndbord[i][1] == 1) &&
((ndbord[i - 1][0] < 1) ||
(groupIDs[i - 1][0] != groupIDs[i][1])) &&
((ndbord[i + 1][0] < 1) ||
(groupIDs[i + 1][0] != groupIDs[i][1])) &&
((ndbord[i - 1][1] == -1) ||
(ndbord[i + 1][1] == -1)))
{
*x = i;
*y = 0;
if (safeMove(*x, *y))
return TRUE;
}
}
if (legal[0][i])
{
if ((ndbord[1][i] == 1) &&
((ndbord[0][i - 1] < 1) ||
(groupIDs[0][i - 1] != groupIDs[1][i])) &&
((ndbord[0][i + 1] < 1) ||
(groupIDs[0][i + 1] != groupIDs[1][i])) &&
((ndbord[1][i - 1] == -1) ||
(ndbord[1][i + 1] == -1)))
{
*x = 0;
*y = i;
if (safeMove(*x, *y))
return TRUE;
}
}
if (legal[i][maxPoint])
{
if ((ndbord[i][maxPoint - 1] == 1) &&
((ndbord[i - 1][maxPoint] < 1) ||
(groupIDs[i - 1][maxPoint] != groupIDs[i][maxPoint - 1])) &&
((ndbord[i + 1][maxPoint] < 1) ||
(groupIDs[i + 1][maxPoint] != groupIDs[i][maxPoint - 1])) &&
((ndbord[i - 1][maxPoint - 1] == -1) ||
(ndbord[i + 1][maxPoint - 1] == -1)))
{
*x = i;
*y = maxPoint;
if (safeMove(*x, *y))
return TRUE;
}
}
if (legal[maxPoint][i])
{
if ((ndbord[maxPoint - 1][i] == 1) &&
((ndbord[maxPoint][i - 1] < 1) ||
(groupIDs[maxPoint][i - 1] != groupIDs[maxPoint - 1][i])) &&
((ndbord[maxPoint][i + 1] < 1) ||
(groupIDs[maxPoint][i + 1] != groupIDs[maxPoint - 1][i])) &&
((ndbord[maxPoint - 1][i - 1] == -1) ||
(ndbord[maxPoint - 1][i + 1] == -1)))
{
*x = maxPoint;
*y = i;
if (safeMove(*x, *y))
return TRUE;
}
}
}
return FALSE;
} /* dropToEdge2 */